import 'dart:convert';
import 'dart:io';
import 'dart:isolate';

import 'package:flutter/material.dart';

class IsolateTest extends StatefulWidget {
  @override
  _IsolateTestState createState() => _IsolateTestState();
}

class _IsolateTestState extends State<IsolateTest>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;
  int i = 0;
  List _sourceList = [
    {'title': '1'},
    {'title': '1'},
    {'title': '1'},
    {'title': '1'},
    {'title': '1'},
    {'title': '1'}
  ];

  int ticket = 10;

  List numsList = [1, 2, 3, 4, 5, 6, 7];
  GlobalKey textButtonKey = GlobalKey();
  GlobalKey outLineButtonKey = GlobalKey();

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this);
  }

  @override
  void dispose() {
    super.dispose();
    _controller.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('isolate'),
        ),
        body: Column(
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                TextButton(
                    key: textButtonKey,
                    onPressed: () {
                      RenderBox textBox =
                          textButtonKey.currentContext.findRenderObject();
                      RenderBox outLineBox =
                          outLineButtonKey.currentContext.findRenderObject();
                      var offset = textBox.localToGlobal(Offset.zero);
                      var outLineoffset = outLineBox.localToGlobal(Offset.zero);
                      // print(offset);
                      // print(outLineoffset);

                      print(textBox.size);
                      print(outLineBox.size);
                      RenderBox renderBox =
                          textButtonKey.currentContext.findRenderObject();
                      RenderBox outLinerenderBox =
                          outLineButtonKey.currentContext.findRenderObject();
                      var offsetRender = renderBox
                          .localToGlobal(Offset(0.0, renderBox.size.height));
                      var offsetRenderOutLine = outLinerenderBox
                          .localToGlobal(Offset(0.0, renderBox.size.height));
                      print(offsetRender);
                      print(offsetRenderOutLine);
                    },
                    child: Text("点击开始")),
                OutlinedButton(
                    key: outLineButtonKey,
                    onPressed: () {
                      // for (var i = 0; i < 30; i++) {
                      // print('开启 ${i.toString()}');
                      var receivePort1 = new ReceivePort();
                      var receivePort2 = new ReceivePort();
                      var receivePort3 = new ReceivePort();
                      mainThreadStar(receivePort1);
                      mainThreadStar(receivePort2);
                      mainThreadStar(receivePort3);
                      // loadData();
                      // }
                    },
                    child: Text('mainThreadStar')),
              ],
            ),
            Expanded(
              child: ListView.builder(
                  padding: const EdgeInsets.all(20),
                  // shrinkWrap: true,
                  itemCount: _sourceList?.length ?? 0,
                  itemBuilder: (BuildContext context, int index) {
                    return Padding(
                      padding: const EdgeInsets.only(top: 8.0, bottom: 8),
                      child: Text(_sourceList[index]['title']),
                    );
                  }),
            ),
          ],
        ));
  }

  loadData() async {
    // 通过spawn新建一个isolate，并绑定静态方法
    ReceivePort receivePort = ReceivePort();
    await Isolate.spawn(dataLoader, receivePort.sendPort);

    // 获取新isolate的监听port
    SendPort sendPort = await receivePort.first;
    // 调用sendReceive自定义方法
    List dataList = await sendReceive(
        sendPort, 'http://jsonplaceholder.typicode.com/posts');
    print('dataList $dataList');
    _sourceList.addAll(dataList);
    setState(() {});
  }

// isolate的绑定方法
  static dataLoader(SendPort sendPort) async {
    // 创建监听port，并将sendPort传给外界用来调用
    ReceivePort receivePort = ReceivePort();
    sendPort.send(receivePort.sendPort);

    // 监听外界调用
    await for (var msg in receivePort) {
      String requestURL = msg[0];
      SendPort callbackPort = msg[1];

      HttpClient client = HttpClient();
      HttpClientRequest request = await client.getUrl(Uri.parse(requestURL));

      var response = await request.close();
      var responseBody = await response.transform(utf8.decoder).join();
      // List dataList = json.decode(response.body);
      // var response = await http.get(requestURL);
      List dataList = json.decode(responseBody);
      // 回调返回值给调用者
      callbackPort.send(dataList);
    }
  }

// 创建自己的监听port，并且向新isolate发送消息
  Future sendReceive(SendPort sendPort, String url) {
    ReceivePort receivePort = ReceivePort();
    sendPort.send([url, receivePort.sendPort]);
    // 接收到返回值，返回给调用者
    return receivePort.first;
  }

  /// 另一个例子

// 第1步：定义主线程
  mainThreadStar(ReceivePort receivePort) async {
    // 第3步：编写回调Port
    await Isolate.spawn(echo, receivePort.sendPort);

    // 第6步：保存隔离线程回调Port
    var sendPort = await receivePort.first;

    // 第7步：发送消息
    var msg = await sendMsgReceive(sendPort, "continue");
    print('received info：$msg');
    // msg = await sendMsgReceive(sendPort, "add");
    // print('received info：$msg');
    // setState(() {
    //   // print(_sourceList);
    //   _sourceList.add({'title': i.toString()});
    //   i++;
    // });
    msg = await sendMsgReceive(sendPort, "sub");
    print('received info：$msg');
    if (ticket > 0) {
      // print('还有 $ticket 张票呢');
      sleep(Duration(milliseconds: 10));
      ticket--;
      print('卖出去一张 还有 $ticket 张票呢');
      // Future.delayed(Duration(milliseconds: 1)).then((value) {

      // });
    } else if (ticket <= 0) {
      msg = await sendMsgReceive(sendPort, "close");
      print('没票了 关了 received info：$msg');
    } else {
      print('进不来');
    }
  }

// 第2步：定义隔离线程的入口点
  static echo(SendPort sendPort) async {
    // 第4步：编写回调Port
    var port = new ReceivePort();

    // 第5步：告诉主线程回调入口点
    sendPort.send(port.sendPort);

    // 第8步：循环接收消息
    await for (var msg in port) {
      // 数组 msg[0] 是数据
      var data = msg[0];
      // 数组 msg[1] 是发送方Port
      SendPort replyTo = msg[1];
      // 回传发送方 数据
      replyTo.send(data);
      // 如果数据时 close 关闭当前回调
      if (data == "close") port.close();
    }
  }

/*
主线程 发送消息函数
数组 msg[0] 是数据
数组 msg[1] 是发送方Port
返回 隔离线程 Port
*/
  Future sendMsgReceive(SendPort port, msg) {
    ReceivePort response = new ReceivePort();
    port.send([msg, response.sendPort]);
    return response.first;
  }

  // void clean() {
  //   _sourceList.clear();
  // }
}
